#pragma once
#include<iostream>
#include"IO.h"
#include"BasicType.h"
using namespace std;

enum DISKTYPE{BLOCK, BLOCKDEL, SLINDEX, BITMAP};

class ResourceInfo{
private:

    DISKTYPE diskType;

    string baseName;   //每个diskType都必须的
    string tableName;  //每个diskType都必须的

    string colName;    //block和index必须的
    int16_t blockNo;       //block和blockdel必须的

    TYPE dataType;      //block, index必须

    double left;          //index BitMap 必须

    void checkNameLen(const string& baseName, const string& tableName, const string& colName = ""){
        const int& nameMaxLen = IOUtil::getNameMaxLen();
        StringUtil::checkLen(baseName, nameMaxLen);
        StringUtil::checkLen(tableName, nameMaxLen);
        StringUtil::checkLen(colName, nameMaxLen);
    }

    void init(const string& baseName, const string& tableName, const string& colName = ""){
        this->baseName = baseName;
        this->tableName = tableName;
        this->colName = colName;
    }

    friend class ResourceInfoUtil; //统一使用ResourceInfoUtil来操作ResourceInfo

public:

    ResourceInfo(){}

    //block
    ResourceInfo(const string& baseName, const string& tableName, const string& colName, const int16_t& blockNo, const TYPE& dataType){
        checkNameLen(baseName, tableName, colName);
        init(baseName, tableName, colName);
        this->blockNo = blockNo;
        this->dataType = dataType;
        this->diskType = BLOCK;
    }

    //blockdel
    ResourceInfo(const string& baseName, const string& tableName, const int16_t& blockNo){
        checkNameLen(baseName, tableName);
        init(baseName, tableName);
        this->blockNo = blockNo;
        this->diskType = BLOCKDEL;
    }

    //index
    ResourceInfo(const string& baseName, const string& tableName, const string& colName, const TYPE& dataType, const double& left){
        checkNameLen(baseName, tableName, colName);
        init(baseName, tableName, colName);
        this->dataType = dataType;
        this->left = left;
        this->diskType = SLINDEX;
    }

    //BitMap
    ResourceInfo(const string& baseName, const string& tableName, const string& colName, const double& left){
        checkNameLen(baseName, tableName, colName);
        init(baseName, tableName, colName);
        this->left = left;
        this->diskType = BITMAP;
    }

    string getRelativePath() const {
        string tableRelativePath = getTableRelativePath(baseName, tableName);
        if(diskType == BLOCK){
            return tableRelativePath + "\\" + colName + "\\" + "blockData" + to_string(blockNo);
        }
        else if(diskType == BLOCKDEL){
            return tableRelativePath + "\\" + "blockDel" + "\\" + to_string(blockNo);
        }
        else if(diskType == SLINDEX){
            return tableRelativePath + "\\" + colName + "\\" + "SLindex" + to_string(left);
        }
        else if(diskType == BITMAP){
            return tableRelativePath + "\\" + colName + "\\" + "BitMap" + to_string(left);
        }
        else{
            throw string("diskType error");
        }
    }

    bool operator==(const ResourceInfo& resInfo) const {
        return this->getRelativePath() == resInfo.getRelativePath();
    }

    bool operator<(const ResourceInfo& resInfo) const {
        return this->getRelativePath() < resInfo.getRelativePath();
    }

    string getFullPath() const {
        return IOUtil::getTotalPath() + "\\" + getRelativePath() + ".bin";
    }

    pair<string, string> getSwitchedFullPaths() const {
        const string& totalPath = IOUtil::getTotalPath(), ralativePath = getRelativePath();
        return make_pair(totalPath + "\\" + ralativePath + "_0" + ".bin",
                         totalPath + "\\" + ralativePath + "_1" + ".bin");
    }

    TYPE getDataType() const {
        return dataType;
    }

    int getDataSize() const {
        return BasicUtil::getDataSize(dataType);
    }

    string getBaseName() const {
        return baseName;
    }

    string getTableName() const {
        return tableName;
    }

    string getColName() const {
        return colName;
    }

    int16_t getBlockNo() const {
        return blockNo;
    }

    DISKTYPE getDiskType() const {
        return diskType;
    }

    static string getTableRelativePath(const string& baseName, const string& tableName) {
        return baseName + "\\" + tableName;
    }

    static string getTableFullPath(const string& baseName, const string& tableName) {
        return IOUtil::getTotalPath() + "\\" + getTableRelativePath(baseName, tableName);
    }
};


bool resInfoCmp(const ResourceInfo& resInfo1, const ResourceInfo& resInfo2){
    return resInfo1.getRelativePath() < resInfo2.getRelativePath();
}


class ResourceInfoUtil{
public:
    static ResourceInfo blockInfoToBlockDelInfo(const ResourceInfo& blockInfo){
        return ResourceInfo(blockInfo.baseName, blockInfo.tableName, blockInfo.blockNo);
    }
};



struct ResInfoHash{
    size_t operator()(const ResourceInfo& resInfo) const {
        return hash<string>()(resInfo.getRelativePath());
    }
};
